package com.promise.jokerdream.manager

import com.promise.jokerdream.model.knight.KnightSkillMapping
import com.promise.jokerdream.repository.GameApi
import com.promise.jokerdream.repository.PhoneGameApi
import com.promise.jokerdream.response.pc.QueryKnightArenaResponse
import com.promise.jokerdream.response.pc.QueryKnightFightResponse
import com.promise.jokerdream.response.phone.FightProcessXmlResponse
import com.promise.jokerdream.utils.UrlFixer
import kotlinx.coroutines.*
import org.jsoup.Jsoup

class FightProcessManager private constructor() {
    
    private val phoneGameApi = PhoneGameApi.getInstance()
    private val gameApi = GameApi.getInstance()
    private var currentJob: Job? = null
    private var currentId: String? = null
    
    companion object {
        @Volatile
        private var INSTANCE: FightProcessManager? = null
        
        fun getInstance(): FightProcessManager {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: FightProcessManager().also { INSTANCE = it }
            }
        }
    }
    
    suspend fun getCompleteFightProcess(
        initialUrl: String,
        onProgress: ((Int, Int, String) -> Unit)? = null
    ): Result<String> {
        val id = extractIdFromUrl(initialUrl)
        
        synchronized(this) {
            if (currentJob?.isActive == true) {
                if (currentId == id) {
                    return Result.failure(Exception("相同ID的任务正在进行中"))
                } else {
                    currentJob?.cancel()
                    currentJob = null
                }
            }
            currentId = id
        }
        
        return coroutineScope {
            val job = async {
                try {
                    // 检查type参数，根据type值请求不同的API
                    var knightFightContent: String? = null
                    val type = extractTypeFromUrl(initialUrl)
                    if (id != null) {
                        knightFightContent = when (type) {
                            "24" -> fetchKnightFightContent(id)
                            "30" -> fetchKnightArenaContent(id)
                            else -> null
                        }
                    }
                    
                    val pages = mutableListOf<FightProcessXmlResponse>()
                    var url = UrlFixer.fixUrl(initialUrl)
                    
                    while (true) {
                        ensureActive()
                        
                        // 如果queryFightProcess失败，一直重试直到成功
                        val page = retryUntilSuccess {
                            phoneGameApi.queryFightProcess(url).getOrNull()
                        }
                        
                        pages.add(page)
                        onProgress?.invoke(page.currentPage, page.totalPages, page.xmlContent)
                        
                        if (page.nextPageLink.isEmpty() || page.currentPage >= page.totalPages) break
                        
                        ensureActive()
                        delay(300)
                        url = page.nextPageLink
                    }
                    
                    ensureActive()
                    
                    if (pages.isEmpty()) {
                        return@async Result.failure(Exception("未获取到任何页面"))
                    }

                    val firstPage = pages.first()
                    val lastPage = pages.last()
                    val allRounds = pages.map { it.rounds }.filter { it.isNotEmpty() }
                    val newContent = firstPage.header + allRounds.joinToString("") + lastPage.footer
                    
                    val doc = Jsoup.parse(lastPage.xmlContent)
                    val div = doc.selectFirst("div#id")
                    if (div != null) {
                        div.html(newContent)
                    }
                    
                    var processedXml = processHpText(doc.html())
                    
                    // 如果成功获取了knightFight的格式化内容，将其添加到最前面
                    if (knightFightContent != null) {
                        processedXml = knightFightContent + "\n\n" + processedXml
                    }
                    
                    Result.success(processedXml)
                } catch (e: CancellationException) {
                    Result.failure(e)
                } catch (e: Exception) {
                    Result.failure(e)
                }
            }
            
            synchronized(this@FightProcessManager) {
                currentJob = job
            }
            
            try {
                job.await()
            } finally {
                synchronized(this@FightProcessManager) {
                    if (currentJob == job) {
                        currentJob = null
                        currentId = null
                    }
                }
            }
        }
    }
    
    fun cancel() {
        synchronized(this) {
            currentJob?.cancel()
            currentJob = null
            currentId = null
        }
    }
    
    fun getCurrentId(): String? = synchronized(this) { currentId }
    
    /**
     * 重试直到成功的辅助函数
     */
    private suspend fun <T> retryUntilSuccess(block: suspend () -> T?): T {
        while (true) {
            yield() // 检查取消状态
            val result = block()
            if (result != null) {
                return result
            }
            // 失败后等待一段时间再重试
            delay(300)
        }
    }
    
    private fun extractIdFromUrl(url: String): String? {
        val idRegex = Regex("[?&]id=([^&]+)")
        return idRegex.find(url)?.groupValues?.get(1)
    }
    
    private fun extractTypeFromUrl(url: String): String? {
        val typeRegex = Regex("[?&]type=([^&]+)")
        return typeRegex.find(url)?.groupValues?.get(1)
    }
    
    private fun processHpText(xmlContent: String): String {
        val hpPattern = Regex("HP([+-])\\d+[^（]*（HP余\\d+）")
        return hpPattern.replace(xmlContent) { matchResult ->
            val sign = matchResult.groupValues[1]
            val color = if (sign == "+") "green" else "red"
            "<span style=\"color: $color;\">${matchResult.value}</span>"
        }
    }
    
    /**
     * 根据type值获取对应的格式化内容
     * @param id 战斗ID
     * @return 格式化后的内容，失败返回null
     */
    private suspend fun fetchKnightFightContent(id: String): String? {
        return gameApi.queryKnightFight(id).fold(
            onSuccess = { response ->
                if (response.result == 0) {
                    buildKnightFightContent(response)
                } else {
                    null
                }
            },
            onFailure = { null }
        )
    }
    
    /**
     * 获取侠士论剑的格式化内容
     * @param id 战斗ID
     * @return 格式化后的内容，失败返回null
     */
    private suspend fun fetchKnightArenaContent(id: String): String? {
        return gameApi.queryKnightArenaFight(id).fold(
            onSuccess = { response ->
                if (response.result == 0) {
                    buildKnightFightContent(response)
                } else {
                    null
                }
            },
            onFailure = { null }
        )
    }
    
    /**
     * 构建群侠战斗的格式化内容（参考testPage的实现）
     */
    private fun buildKnightFightContent(response: QueryKnightFightResponse): String? {
        // 解析玩家阵容信息
        val formations = response.parseFirstFightFormations() ?: return null
        
        val player1 = formations.first
        val player2 = formations.second
        val fightRecords = formations.third
        
        // 获取玩家ID（使用第一个侠士的ID）
        val player1Id = player1.knights.firstOrNull()?.id ?: ""
        val player2Id = player2.knights.firstOrNull()?.id ?: ""
        
        // 构建XML格式的显示内容
        val redSpan = "<span style=\"color: red;\">"
        val greenSpan = "<span style=\"color: green;\">"
        val blueSpan = "<span style=\"color: #0D47A1;\">"  // onPrimaryContainer 深蓝色
        val spanEnd = "</span>"
        
        return buildString {
            append("<div>")
            
            // 获取最后一场战斗的结果
            val lastFightResult = fightRecords.lastOrNull()?.result?.winner
            val (resultText, resultColor) = when (lastFightResult) {
                0 -> "胜" to "red"  // Player1获胜
                1 -> "负" to "green"  // Player2获胜
                else -> "未知" to ""
            }
            val coloredResultText = if (resultColor.isNotEmpty()) {
                if (resultColor == "red") {
                    "战斗结果: $redSpan$resultText$spanEnd"
                } else {
                    "战斗结果: $greenSpan$resultText$spanEnd"
                }
            } else {
                "战斗结果: $resultText"
            }
            append("<div>$coloredResultText</div>")
            
            // 先展示双方侠士
            append("<div>侠士阵容($player1Id)</div>")
            player1.knights.forEachIndexed { index, knight ->
                val skillNames = knight.skills.map { skillId ->
                    KnightSkillMapping.getNameById(skillId) ?: "未知($skillId)"
                }
                append("<div>${index + 1}.${knight.name}(等级:${knight.level},血:${redSpan}${knight.hp}${spanEnd},力:${blueSpan}${knight.strength}${spanEnd},速:${blueSpan}${knight.speed}${spanEnd},敏:${blueSpan}${knight.agility}${spanEnd})</div>")
                append("<div style=\"white-space: pre-wrap;\">    [${skillNames.joinToString(",")}]</div>")
            }
            
            append("<div><br/></div>")
            append("<div>侠士阵容($player2Id)</div>")
            player2.knights.forEachIndexed { index, knight ->
                val skillNames = knight.skills.map { skillId ->
                    KnightSkillMapping.getNameById(skillId) ?: "未知($skillId)"
                }
                append("<div>${index + 1}.${knight.name}(等级:${knight.level},血:${redSpan}${knight.hp}${spanEnd},力:${blueSpan}${knight.strength}${spanEnd},速:${blueSpan}${knight.speed}${spanEnd},敏:${blueSpan}${knight.agility}${spanEnd})</div>")
                append("<div style=\"white-space: pre-wrap;\">    [${skillNames.joinToString(",")}]</div>")
            }
            
            // 然后展示每一场战斗记录的结果
            append("<div><br/></div>")
            append("<div>侠士战斗记录</div>")
            fightRecords.forEachIndexed { index, record ->
                val (resultText, resultColor) = when (record.result.winner) {
                    0 -> "胜" to "red"  // Player1获胜
                    1 -> "负" to "green"  // Player2获胜
                    else -> "未知" to ""
                }
                
                val coloredResultText = if (resultColor.isNotEmpty()) {
                    if (resultColor == "red") {
                        "$redSpan$resultText$spanEnd"
                    } else {
                        "$greenSpan$resultText$spanEnd"
                    }
                } else {
                    resultText
                }
                
                // 获取每次战斗的侠士信息
                val player1Knight = record.player1Formation.knights.firstOrNull()
                val player2Knight = record.player2Formation.knights.firstOrNull()
                
                if (player1Knight != null && player2Knight != null) {
                    append("<div>($coloredResultText) ${player1Knight.name}(血:${redSpan}${player1Knight.hp}${spanEnd}) vs ${player2Knight.name}(血:${redSpan}${player2Knight.hp}${spanEnd})</div>")
                } else {
                    append("<div>($coloredResultText) ${record.player1Formation.knights.joinToString(", ") { it.name }} vs ${record.player2Formation.knights.joinToString(", ") { it.name }}</div>")
                }
            }

            append("<div><br/></div>")
            append("</div>")
        }
    }
}
